﻿//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Microsoft Public License.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace AstoriaOverAstoriaTests
{
    using System;
    using System.Diagnostics;
    using System.Xml.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System.Net;
    using System.IO;
    using System.Xml;
    using System.Data.Services;

    public static class AoATestUtil
    {
        public static readonly string MimeTextPlain = "tExt/plaIn";

        public static XNamespace AtomNs = XNamespace.Get("http://www.w3.org/2005/Atom");

        private static XDocument GetResponseFromService(Type dataServiceType, string uri, out Exception exception, out HttpStatusCode responseStatusCode)
        {
            exception = null;
            responseStatusCode = HttpStatusCode.Forbidden;  // Some weird error code, so that it doesn't match anything we should get otherwise

            Type type = dataServiceType;
            Type serviceType = null;
            while (type != null && type != typeof(object))
            {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(DataService<>))
                {
                    serviceType = dataServiceType;
                    break;
                }

                type = type.BaseType;
            }

            if (serviceType == null)
            {
                serviceType = typeof(TestDataService<>).MakeGenericType(dataServiceType);
            }

            XDocument responsePayload = null;
            using (TestService service = new TestService(serviceType))
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(service.ServiceUri.ToString() + uri));
                HttpWebResponse response;
                try
                {
                    response = (HttpWebResponse)request.GetResponse();

                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        using (Stream responseStream = response.GetResponseStream())
                        {
                            string contentType = response.ContentType;
                            if (contentType != null)
                            {
                                int contentTypeSemicolonIndex = contentType.IndexOf(';');
                                if (contentTypeSemicolonIndex >= 0)
                                {
                                    contentType = contentType.Substring(0, contentTypeSemicolonIndex);
                                }
                            }

                            if (contentType != null && string.Equals(contentType, AoATestUtil.MimeTextPlain, StringComparison.OrdinalIgnoreCase))
                            {
                                string value = (new StreamReader(responseStream)).ReadToEnd();
                                responsePayload = new XDocument(new XElement("value", value));
                            }
                            else
                            {
                                using (XmlReader reader = XmlReader.Create(responseStream))
                                {
                                    responsePayload = XDocument.Load(reader);
                                }
                            }
                        }
                    }
                    else if (response.StatusCode == HttpStatusCode.NoContent)
                    {
                        responsePayload = null;
                    }
                    else
                    {
                        Assert.Fail("Unexpected response status code {0}", response.StatusCode);
                    }
                }
                catch (WebException webException)
                {
                    exception = webException;
                    response = webException.Response as HttpWebResponse;
                }

                responseStatusCode = response.StatusCode;
            }

            return responsePayload;
        }

        public static void VerifyGetResponse(Type dataServiceType, string uri)
        {
            IAoATestService aoaservice = (IAoATestService)Activator.CreateInstance(dataServiceType);

            Trace.WriteLine(uri);

            // Get the response from the underlying service
            Exception underlyingException;
            HttpStatusCode underlyingStatusCode;
            XDocument underlyingResponse = GetResponseFromService(aoaservice.UnderlyingServiceType, uri, out underlyingException, out underlyingStatusCode);

            // Get the response from the AoA service
            Exception aoaException = null;
            HttpStatusCode aoaStatusCode;
            XDocument aoaResponse = GetResponseFromService(dataServiceType, aoaservice.PrepareRequestUri(uri), out aoaException, out aoaStatusCode);

            if (underlyingException != null)
            {
                Assert.IsNotNull(aoaException, "Underlying failed with exception but AoA didn't. Underlying exception: " + underlyingException.ToString());
                Assert.AreEqual(underlyingStatusCode, aoaStatusCode, "The underlying service returend different response status code than AoA.");
            }
            else
            {
                Assert.IsNull(aoaException, "AoA failed with unexpected exception: " + (aoaException == null ? "null" : aoaException.ToString()));
            }

            AtomComparer.VerifyEqual(underlyingResponse, aoaResponse);
        }
    }
}